# -*- coding: utf-8 -*-
import re

from django import template
from django.utils.safestring import mark_safe
from django.utils.html import conditional_escape
from django.template.defaultfilters import stringfilter, timesince, pluralize
from django.core.urlresolvers import reverse
from django.conf import settings

from timezones.utils import localtime_for_timezone
import time
import datetime

from utils.stemmer import PorterStemmer

register = template.Library()
 
@register.filter
def in_list(value,arg):
    return value in arg

@register.filter
def startswith(value,arg):
    return value.startswith(arg)

@register.filter
def strip_html(text):
    text = re.sub("(?:<[^>]*>|\s)+", " ", text)
    for k, v in {"&quot;": '"', "&#39;":'"', "&nbsp;":" ", "&gt;":">",
                 "&lt;":"<", "&amp;":"&"}.iteritems():
        text = text.replace(k, v)
    return text

@register.filter
def join_nicer(value, arg1=", ", arg2="&"):
    value = map(str, list(value))
    if len(value) > 1:
        return "%s %s %s" % (arg1.join(value[:-1]), arg2, value[-1])
    elif len(value) == 1:
        return value[0]
    else:
        return ""

@register.filter
def userlink(user):
    """
    creates a link to a user showing it's displayname
    """
    p = user.get_profile()
    return mark_safe('<a href="%s" class="userlink">%s</a>' % 
                                         (p.get_absolute_url(), p.display_name))                                        


@register.filter
def userlist(ulist):
    ulist = map(userlink, ulist)
    if len(ulist) > 1:
        return mark_safe("%s &amp; %s" % (", ".join(ulist[:-1]), ulist[-1]))
    elif len(ulist) == 1:
        return ulist[0]
    else:
        return ""

@register.simple_tag
def taglist(tlist, url, rel_tag=None):
    tlist = ['<a href="%s"%s>%s</a>' % 
        (reverse(url, kwargs={"tag":tag.name}),
         " title='%s snippet%s tagged with %s and %s'" %
           (tag.count, pluralize(tag.count), rel_tag, tag) if rel_tag else "",
         tag.name) for tag in tlist]
    if len(tlist) > 1:
        return mark_safe("%s &amp; %s" % (", ".join(tlist[:-1]), tlist[-1]))
    elif len(tlist) == 1:
        return mark_safe(tlist[0])
    else:
        return ""


@register.filter
def localtime(value, request, show_since=True):
    if request.user.is_authenticated():
        tz = request.user.get_profile().time_zone
        js = ""
    else:
        tz = settings.TIME_ZONE
        seconds = time.mktime(value.timetuple())
        seconds += (value.microsecond / 1000000.0)
        js = " onload='localtime(%i, this);'" % (seconds * 1000)
    loc_dt = localtime_for_timezone(value, tz)
    dt_str = loc_dt.strftime(settings.SITE_DATETIME_FORMAT)
    title = " title='%s ago'" % timesince(value) if show_since else ""
    return mark_safe("<span class='datetime'%s%s>%s </span>" % 
                     (title, js, dt_str))
 


@register.simple_tag
def adminbox_add(request, app_label, model_name):
    """
    """
    if not request.user.has_perm("%s.add_%s" % (app_label, model_name)):
        return ""
    return "<div class='adminbox adminaddbox'><a href='%s'>%s</a></div>" %(
               reverse("admin:%s_%s_add" % (app_label, model_name)),
               "add %s" % model_name)
               
adminbox_add.allow_tags = True
    
    
@register.simple_tag
def adminbox_change(request, obj):
    app_label, model_name = (obj._meta.app_label, obj._meta.module_name)
    links = []
    for url_part, perm in (("edit","change"), ("delete", "delete")):
        if request.user.has_perm("%s.%s_%s" % (app_label, perm, model_name)):
            url = reverse('admin:%s_%s_%s' % (app_label, model_name, perm),
                          args=[obj.id])
            links.append("<a href='%s'>%s</a>" % (url, perm))
    if links:
        return "<div class='adminbox adminchangebox'>%s</div>" % " ".join(links)    
    return ""

adminbox_change.allow_tags = True


@register.simple_tag
def active(request, pattern):
    if pattern == "#userprofile":
        if request.path == request.user.get_profile().get_absolute_url():
            return 'active'
    elif re.search(pattern, request.path):
        return 'active'
    return ''


@register.inclusion_tag('utils/pagination.html', takes_context=True)
def paginator(context, adjacent_pages=2):
    """
    To be used in conjunction with the object_list generic view.

    Adds pagination context variables for use in displaying first, adjacent and
    last page links in addition to those created by the object_list generic
    view.

    """
    page_obj = context['page_obj']
    paginator = context['paginator']
    first = max(page_obj.number - adjacent_pages - max(page_obj.number+adjacent_pages-paginator.num_pages,0), 1)
    last = min(page_obj.number + adjacent_pages - min(page_obj.number-adjacent_pages-1,0), paginator.num_pages)
    page_numbers = range(first, last+1) #[n for n in \
                   # range(first, last+1)\
                   # if n > 0 and n <= paginator.num_pages]
                    
  #  page_numbers = range(max(0, context['page']-adjacent_pages), min(context['pages'], context['page']+adjacent_pages)+1)                     
    request = context['request']
    request_path = "%s?%s" % (request.path,
                        "".join(["%s=%s&" % (k, v) 
                          for k, v in request.GET.iteritems() if k != "page"]))
    
    return {
        'is_paginated': page_obj.has_other_pages(),
        'hits': paginator.count,
        'results_per_page': paginator.per_page,
        'page': page_obj.number,
        'pages': paginator.num_pages,
        'page_numbers': page_numbers,
        'next': page_obj.next_page_number(),
        'previous': page_obj.previous_page_number(),
        'has_next': page_obj.has_next(),
        'has_previous': page_obj.has_previous(),
        'show_first': 1 not in page_numbers,
        'show_last': paginator.num_pages not in page_numbers,
        "request_path": request_path
    }



# http://www.djangosnippets.org/snippets/1213/

from pygments import highlight
from pygments.lexers import *
from pygments.formatters import HtmlFormatter

@register.tag(name='code')
def do_code(parser,token):
    code = token.split_contents()[-1]
    nodelist = parser.parse(('endcode',))
    parser.delete_first_token()
    return CodeNode(code,nodelist)
    
class CodeNode(template.Node):
    def __init__(self,lang,code):
        self.lang = lang
        self.nodelist = code
        
    def render(self,context):
        try:        
            language = template.Variable(self.lang).resolve(context)
        except:
            language = self.lang
        code = self.nodelist.render(context)
        try:
            lexer = get_lexer_by_name(language)
        except:
            try:
                lexer = guess_lexer(code)
            except:
                lexer = PythonLexer()
        return highlight(code,lexer,HtmlFormatter(noclasses=True))
    
    

@register.filter
def is_online(user):
    """
    Returns if a user was requested a page within the last
    MINUTES_UNTIL_OFFLINE minutes
    """
    if (datetime.datetime.now() - user.last_login
                < datetime.timedelta(minutes=settings.MINUTES_UNTIL_OFFLINE)):
        return True
    return False


#@register.filter
#def process_search_result(string, pattern):
#    """
#    Marks keywords in search results with a css class "searchpattern" for
#    highlighting and shortens the text between them.
#    """
#    opentag, closetag = '<span class="searchpattern">', '</span>'
#    terms = "\\b%s\\b" % "\\b|\\b".join([term.replace('"', '') 
#                        for term in re.findall('("[^"]+"|[^ ]+)', str(pattern))
#                            if not term.startswith("-")])
#    search_terms = re.compile("(?si).{0,50}?(?:%s)(?:.{0,100}?(?:%s))*.{0,50}"
#                                                              % (terms, terms))
#    to_highlight = re.compile("(^|[^\w])(%s)([^\w]|$)"%terms, re.I|re.S)
#    highlighted = "\\1%s\\2%s\\3" % (opentag, closetag)
#    retval = "...".join([to_highlight.sub(highlighted, match) 
#                          for match in search_terms.findall(string)])
#    if not (retval.startswith(string[:5]) or retval.startswith(opentag)):
#       retval = "..."+retval
#    if not (retval.endswith(string[-5:]) or retval.endswith(closetag)):
#       retval += "..."
#    return mark_safe(retval)

# by MizardX@freenode
@register.filter
def process_search_result(string, pattern):
  """
  Marks keywords in search results with a css class "searchpattern" for
  highlighting and shortens the text between them.
  """
  stemmer = PorterStemmer()
  try:
    search_terms = [
        match.group(2) or match.group(1)
        for match in re.finditer(r'"([^"]+)"|(\S+)', str(pattern))
        if match.group(1) is not None or not match.group(2).startswith("-")
    ]
    stemmed_search_terms = [stemmer.stem(term, 0, len(term)-1)
                                        for term in search_terms]
    search_terms = '|'.join(
        r'%s%s%s' % (
            r'\w*?\b' if term[0].isalnum() else '',
            "%s%s" % (term, "\w*?" if term!=orig_term else ""),
            r'\w*?\b' if term[-1].isalnum() else ''
        )
        for term, orig_term in zip(stemmed_search_terms, search_terms)
    )
    regions = r'.{0,50}?(?:%s)(?:.{0,100}?(?:%s))*.{0,50}' % (search_terms, search_terms)
    regions_re = re.compile(regions, re.IGNORECASE | re.DOTALL)
    highlight_re = re.compile('(%s)' % (search_terms,), re.IGNORECASE | re.DOTALL)
    highlighted = r'<span class="searchpattern">\1</span>'
    hits = list(regions_re.finditer(string))
    max_length = 500
    sum_length = len(hits[0].group())
    stop = 1
    for stop in xrange(1,len(hits)):
        if sum_length > max_length:
            break
        sum_length += 3 + len(hits[stop].group())
    del hits[stop:]
    retval = "...".join(
      highlight_re.sub(highlighted, hit.group())
      for hit in hits
    )
    prefix = suffix = ""
    if hits[0].start() > 0:
       prefix = "..."
    if hits[-1].end() < len(string):
       suffix = "..."
    retval = '%s%s%s' % (prefix, retval, suffix)
    return mark_safe(retval)
  except Exception, e:
      if settings.DEBUG:
          print "error in process_search_result:", e
          raise
      return len(string) < 100 and string or "%s..." % string[:100]


# only for debugging, really
@register.filter(name='dir')
def dirfilter(arg):
    return dir(arg)
